﻿/**
 * @file Tip.js
 * @description
 *	custom tip layer control
 * $id:v1.0.0, 2009-03-02 14:03, baboo<istxwang@gmail.com>$
 */
(function ($) {

$.Tip = $({
	__init: function (sets) {
		this.sets = $.extend({
			//delay seconds that show the tip
			delay: 0,
			delayHide: 0,
			zIndex: 1000,
			deltaX:5,
			deltaY: 5,
			effect: false
		}, sets);
		this.$cnt = this.sets.$cnt;
		this.$cnt.css({position:'absolute', 'z-Index': this.sets.zIndex, display:'none'});
		
		if (this.sets.delayHide != 0) {
			this.$cnt.mouseenter(this._mouseenterTip.bind(this));
			this.$cnt.mouseleave(this._mouseleaveTip.bind(this));
		}
	},
	_mouseenterTip: function() {
		if (this.hideTimer) {
			clearTimeout(this.hideTimer);
			this.hideTimer = null;	
		}	
		(this.sets.onMouseenterTip || $.nothing) (this);
	},
	_mouseleaveTip: function () {
		(this.sets.onMouseleaveTip || $.nothing) (this);
		this.hide();
	},
	_setPosition: function (x, y, ey) {
		var viewSize = {
			width: document.documentElement.clientWidth || document.body.clientWidth, 
			height: document.documentElement.clientHeight || document.body.clientHeight
		};
		var tipSize = this._tipSize();	
		var left = x, top = y, dx = this.sets.deltaX, dy = this.sets.deltaY + Math.round(ey/2), tw = tipSize.width, th = tipSize.height;
		var px =  window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
    		var py =  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
		var pos;
		var cannotbe = [top -py - dy - th < 0 ? 't' : '', left - px + dx + tw > viewSize.width ? 'r' : '', 
				     top - py + dy + th > viewSize.height ? 'b' : '', left - px - dx - tw < 0 ? 'l' : ''];
		pos = cannotbe.include('t') ? 'b' : 't';
		pos += cannotbe.include('r') ? 'l' : 'r';
		switch (pos) {
			  case 'bl':
			    	left -= (tw + dx);
			    	top += dy;
			    	break;
			  case 'br':
			    	left += dx;
			    	top += dy;
			    	break;
			  case 'tl':
			    	left -= (tw + dx);
			    	top -= (th + dy);
			    	break;
			  case 'tr':
			  default:
			    	left += dx;
			    	top -= (th + dy); 	
		}
		this.$cnt.css({left: left + 'px', top: top + 'px'});
	},
	_tipSize: function () {
		var ret;
		if (this.sets.width && this.sets.height) {
			ret = {
				width: this.sets.width,
				height: this.sets.height
			};
		} else {
			ret = this.$cnt.dimentions();
		}
		return ret;	
	},
	content: function (c) {
		if (this.sets.process)
			c = this.sets.process(c);
		this.$cnt.html(c);	
	},
	hide: function () {
		this.__show = false;
		if (this.showTimer) {
			clearTimeout(this.showTimer);
			this.showTimer = null;
			return this;
		}
		if (this.sets.delayHide && !this.hideTimer) {
			this.hideTimer = this.hide.bind(this).delay(this.sets.delayHide);
			return this;
		}
		this.hideTimer = null;
		(this.sets.onBeforeHide || $.nothing) (this);
		this.$cnt.hide();
		return this;
	},
	follow: function (event) {
		if (!this.__show) this.show(event, arguments[1]);
		x = event.pageX, y = event.pageY, ey = event.target.offsetHeight || 0;
		this._setPosition(x, y, ey);
		return this;
	},
	show: function (event) {
		if (!event.timerCall && this.__show) return this;
		this.__show = true;
		var x, y, ey;
		if (!event.timerCall) {
			x = event.pageX;
			y = event.pageY;
			ey = event.target.offsetHeight || 0;
		}
		if (this.hideTimer) {
			clearTimeout(this.hideTimer);
			this.hideTimer = null;
			this.$cnt.hide();	
		}
		if (this.sets.delay !== 0) {
			if (this.showTimer && !event.timerCall) {
				clearTimeout(this.showTimer);
				this.showTimer = null;
			}
			if (!this.showTimer) {
				this.showTimer = this.show.bind(this).delay(this.sets.delay, {timerCall: 1, x: x, y: y, ey: ey}, arguments[1]);
				return this;	
			} 
			this.showTimer = null;
			x = event.x;
			y = event.y;
			ey = event.ey;	
		} 
		if (arguments[1]) this.content(arguments[1]);
		this._setPosition(x, y, ey);
		(this.sets.onBeforeShow || $.nothing) (this);
		this.$cnt.show();
		return this;
	}		
});
	
})($imple);